In [ ]:
from tensorflow import keras
from tensorflow.keras import layers
import pathlib
from tensorflow.keras.utils import image_dataset_from_directory

import pandas as pd
import pathlib
from pathlib import Path

import numpy as np
import pandas as pd

# plotting modules
from matplotlib import pyplot as plt
import seaborn as sns

from sklearn.model_selection import train_test_split

import plotly as plotly
plotly.offline.init_notebook_mode()

from tensorflow import keras
from tensorflow.keras import layers

import tensorflow as tf
from keras.utils import to_categorical
from keras.models import load_model
from PIL import Image

import plotly.graph_objects as go
from tensorflow.keras.models import Sequential
from keras.callbacks import ModelCheckpoint
from tensorflow.keras.layers import Dense
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, classification_report, precision_recall_curve, ConfusionMatrixDisplay

Framing the Problem¶

The purpose of this notebook is to help farmers and everyone really, to identify a plant using a picture of its leaf/leaves.

Getting the data¶

The dataset that we will be training our models on is gotten from Kaggle - https://www.kaggle.com/datasets/sadmansakibmahi/plant-disease-expert/data

In [ ]:
data_folder = pathlib.Path("../../../../../../Downloads/datasets/plant-id")
In [ ]:
def create_image_dataframe(folder):
    data = {'ImagePath': [], 'ClassLabel': []}
    for class_folder in folder.iterdir():
        if class_folder.is_dir():
            for img_path in class_folder.iterdir():
                data['ImagePath'].append(img_path)
                data['ClassLabel'].append(class_folder.name)
    return pd.DataFrame(data)
In [ ]:
df = create_image_dataframe(data_folder)
In [ ]:
df
Out[ ]:
ImagePath ClassLabel
0 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Apple
1 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Apple
2 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Apple
3 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Apple
4 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Apple
... ... ...
35375 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Tomato
35376 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Tomato
35377 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Tomato
35378 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Tomato
35379 ..\..\..\..\..\..\Downloads\datasets\plant-id\... Tomato

35380 rows × 2 columns

As we can see from the above, we have 35,380 images in all the folders combined.

The class labels represent each of the folders we have in our downloaded folder.

In [ ]:
len(df['ClassLabel'].unique())
Out[ ]:
10

We have 10 folders, which is the number of classes or plant species that we have in this dataset.

In [ ]:
df['ClassLabel'].value_counts()
Out[ ]:
ClassLabel
Grape           12345
Potato           4145
Apple            3948
Tomato           3819
Pepper bell      3549
Corn (maize)     2790
Cherry           2052
Strawberry       1511
Tea               861
Rice              360
Name: count, dtype: int64

Exploratory Data Analysis¶

Let us put our dataset to view.

In [ ]:
import matplotlib.pyplot as plt
from PIL import Image

grouped = df.groupby('ClassLabel')

# Plot the first 5 images for each class
for label, group in grouped:
    print(label)
    print('=====================')
    
    # Create a figure with 5 subplots (1 row, 5 columns)
    fig, axes = plt.subplots(1, 5, figsize=(20, 4))
    
    # Iterate over the first 5 rows of the group
    for i in range(min(5, len(group))):  # This ensures we don't go out of bounds if there are less than 5 images
        img_path = group['ImagePath'].iloc[i]
        img = Image.open(img_path)
        
        # Plot the image in the i-th subplot
        axes[i].imshow(img)
        axes[i].set_title(label)
        axes[i].axis('off')
    
    # Hide any unused subplots if the group has less than 5 images
    if len(group) < 5:
        for j in range(len(group), 5):
            axes[j].axis('off')
    
    plt.show()
Apple
=====================
No description has been provided for this image
Cherry
=====================
No description has been provided for this image
Corn (maize)
=====================
No description has been provided for this image
Grape
=====================
No description has been provided for this image
Pepper bell
=====================
No description has been provided for this image
Potato
=====================
No description has been provided for this image
Rice
=====================
No description has been provided for this image
Strawberry
=====================
No description has been provided for this image
Tea
=====================
No description has been provided for this image
Tomato
=====================
No description has been provided for this image

Modeling¶

Before we train our model, we need to prepare our images to the format that the model expects.

In [ ]:
df['ImagePath'] = df['ImagePath'].astype(str)
grouped = df.groupby('ClassLabel')

train_df = pd.DataFrame()
val_df = pd.DataFrame()
test_df = pd.DataFrame()

for _, group in grouped:
    # Split into train and temporary test
    train_tmp, test_tmp = train_test_split(group, test_size=0.3, random_state=42)  # 70% train, 30% temp test
    
    # Split the temporary test into actual validation and test
    val_tmp, test_final = train_test_split(test_tmp, test_size=0.5, random_state=42)  # Split 30% into 15% val, 15% test

    # Append to the respective DataFrames
    train_df = pd.concat([train_df, train_tmp])
    val_df = pd.concat([val_df, val_tmp])
    test_df = pd.concat([test_df, test_final])

# Now, you have train_df, val_df, and test_df
print(f"Training Set: {train_df.shape[0]} samples")
print(f"Validation Set: {val_df.shape[0]} samples")
print(f"Test Set: {test_df.shape[0]} samples")
Training Set: 24762 samples
Validation Set: 5307 samples
Test Set: 5311 samples

Here, we are applying some data augmentation to the dataset to help improve the performance of the model.

We apply some rotation to the images, move the width and heirght around a bit, also flipping them and inverting them.

Another very important step you can see below is that we have rescaled the rgb values of the images from 0 - 256 to values just between 0 and 1. This is an important step because it makes sure that the model doesn't assign more weights to the pixels with very high values.

In [ ]:
from tensorflow.keras.preprocessing.image import ImageDataGenerator

def add_noise(image):
    noise = tf.random.normal(shape=tf.shape(image), mean=0.0, stddev=0.05, dtype=tf.float32)
    return image + noise

def color_jitter(image):
    image = tf.image.random_hue(image, 0.08)
    image = tf.image.random_saturation(image, 0.6, 1.6)
    image = tf.image.random_brightness(image, 0.05)
    image = tf.image.random_contrast(image, 0.7, 1.3)
    return image

def resize_and_crop(image):
    # Resize the image to a larger size to ensure we can crop properly
    image = tf.image.resize(image, [180, 180])
    # Randomly crop the image to the target size
    image = tf.image.random_crop(image, size=[150, 150, 3])
    return image

def preprocessing_function(image):
    image = resize_and_crop(image)
    image = add_noise(image)
    image = color_jitter(image)
    return image

train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=30,  # Randomly rotate images in the range (degrees, 0 to 180)
    width_shift_range=0.2,  # Randomly shift images horizontally (fraction of total width)
    height_shift_range=0.2,  # Randomly shift images vertically (fraction of total height)
    zoom_range=0.2,  # Randomly zoom images
    brightness_range=[0.8, 1.2],  # Randomly change brightness
    horizontal_flip=True,  # Randomly flip images horizontally
    vertical_flip=True,  # Randomly flip images vertically
    preprocessing_function=preprocessing_function  # Custom preprocessing
)

val_datagen = ImageDataGenerator(rescale=1./255)
In [ ]:
train_generator = train_datagen.flow_from_dataframe(
    dataframe=train_df,
    x_col="ImagePath",
    y_col="ClassLabel",
    batch_size=32,
    seed=42,
    shuffle=True,
    class_mode="categorical",
    target_size=(150,150))

valid_generator = val_datagen.flow_from_dataframe(
    dataframe=val_df,
    x_col="ImagePath",
    y_col="ClassLabel",
    batch_size=32,
    seed=42,
    shuffle=True,
    class_mode="categorical",
    target_size=(150,150))

test_generator = val_datagen.flow_from_dataframe(
    dataframe=test_df,
    x_col="ImagePath",
    y_col="ClassLabel",
    batch_size=32,
    seed=42,
    shuffle=False,
    class_mode="categorical",
    target_size=(150,150))
Found 24762 validated image filenames belonging to 10 classes.
Found 5307 validated image filenames belonging to 10 classes.
Found 5311 validated image filenames belonging to 10 classes.

Convolutional Neural Network Model¶

With tensorflow and keras, we will be using a fully connected neural network for our model.

In [ ]:
from tensorflow import keras
from tensorflow.keras import layers

inputs = keras.Input(shape=(150, 150, 3))
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(10, activation="softmax")(x)  # 
model = keras.Model(inputs=inputs, outputs=outputs)

Model Explainability¶

Model Architecture and Training Overview¶

We've constructed a neural network model using TensorFlow and Keras, designed specifically for image classification. This model processes images sized 150x150 pixels with 3 color channels (RGB).

Model Layers:

The model starts with a series of convolutional layers, where each layer is designed to detect specific features in the image like edges, textures, or more complex patterns as we go deeper.

Each convolutional layer is followed by a max-pooling layer, which reduces the spatial dimensions of the image representations, helping to make the detection of features invariant to scale and orientation changes.

After multiple layers of convolutions and pooling, the high-level understanding of the images is flattened into a vector that serves as input to a fully connected layer.

Output Layer:

The final layer is a dense layer with 10 units, corresponding to the number of categories we want to classify. It uses the softmax activation function to output probabilities for each class, indicating the likelihood of the image belonging to each class.

Model Compilation:

The model uses the Adam optimizer for adjusting weights, which is effective and efficient for this kind of problem. It minimizes a function called categorical crossentropy, a common choice for classification tasks, which measures the difference between the predicted probabilities and the actual distribution of the labels. We track the accuracy during training as a straightforward metric to understand how well the model performs.

Training Process Enhancements¶

To optimize training and avoid common pitfalls:

ModelCheckpoint: Saves the best model as we train, ensuring that we always have the version of the model that performed best on the validation set, in case later iterations perform worse.

EarlyStopping: Monitors the model's performance on a validation set and stops training if the model's performance doesn't improve for 10 consecutive epochs. This prevents overfitting and unnecessary computation by stopping when the model isn't learning anymore.

ReduceLROnPlateau: Reduces the learning rate if the validation loss stops improving. Smaller steps in weight updates can lead to better fine-tuning and better overall model performance.

Execution¶

The model is trained using the specified training and validation datasets for 15 epochs, but training can stop early if no improvement is seen as monitored by our callbacks. This setup ensures that the training is both efficient and effective, adapting to the data as needed.

In [ ]:
model.summary()
Model: "model_4"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_5 (InputLayer)        [(None, 150, 150, 3)]     0         
                                                                 
 conv2d_99 (Conv2D)          (None, 148, 148, 32)      896       
                                                                 
 max_pooling2d_8 (MaxPooling  (None, 74, 74, 32)       0         
 2D)                                                             
                                                                 
 conv2d_100 (Conv2D)         (None, 72, 72, 64)        18496     
                                                                 
 max_pooling2d_9 (MaxPooling  (None, 36, 36, 64)       0         
 2D)                                                             
                                                                 
 conv2d_101 (Conv2D)         (None, 34, 34, 128)       73856     
                                                                 
 max_pooling2d_10 (MaxPoolin  (None, 17, 17, 128)      0         
 g2D)                                                            
                                                                 
 conv2d_102 (Conv2D)         (None, 15, 15, 256)       295168    
                                                                 
 max_pooling2d_11 (MaxPoolin  (None, 7, 7, 256)        0         
 g2D)                                                            
                                                                 
 conv2d_103 (Conv2D)         (None, 5, 5, 256)         590080    
                                                                 
 flatten_1 (Flatten)         (None, 6400)              0         
                                                                 
 dense_7 (Dense)             (None, 10)                64010     
                                                                 
=================================================================
Total params: 1,042,506
Trainable params: 1,042,506
Non-trainable params: 0
_________________________________________________________________
In [ ]:
model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    metrics=['accuracy']
)
In [ ]:
# Define callbacks
from tensorflow.keras import optimizers, callbacks

my_callbacks = [
    callbacks.ModelCheckpoint(filepath='./models/newer/vanilla.h5', save_best_only=True),
    callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
    callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]
In [ ]:
history = model.fit(
    train_generator,
    validation_data=valid_generator,
    epochs=30,
    callbacks=my_callbacks
)
Epoch 1/30
774/774 [==============================] - 1095s 1s/step - loss: 1.3464 - accuracy: 0.5453 - val_loss: 2.2064 - val_accuracy: 0.4536 - lr: 0.0010
Epoch 2/30
774/774 [==============================] - 1919s 2s/step - loss: 0.6518 - accuracy: 0.7783 - val_loss: 1.7659 - val_accuracy: 0.6514 - lr: 0.0010
Epoch 3/30
774/774 [==============================] - 315s 407ms/step - loss: 0.4234 - accuracy: 0.8592 - val_loss: 0.7866 - val_accuracy: 0.8059 - lr: 0.0010
Epoch 4/30
774/774 [==============================] - 297s 384ms/step - loss: 0.3322 - accuracy: 0.8910 - val_loss: 0.5070 - val_accuracy: 0.8660 - lr: 0.0010
Epoch 5/30
774/774 [==============================] - 298s 385ms/step - loss: 0.2633 - accuracy: 0.9139 - val_loss: 0.2042 - val_accuracy: 0.9335 - lr: 0.0010
Epoch 6/30
774/774 [==============================] - 295s 381ms/step - loss: 0.2423 - accuracy: 0.9215 - val_loss: 0.6220 - val_accuracy: 0.8681 - lr: 0.0010
Epoch 7/30
774/774 [==============================] - 295s 381ms/step - loss: 0.2083 - accuracy: 0.9331 - val_loss: 0.4237 - val_accuracy: 0.8852 - lr: 0.0010
Epoch 8/30
774/774 [==============================] - 295s 382ms/step - loss: 0.1835 - accuracy: 0.9408 - val_loss: 0.1222 - val_accuracy: 0.9668 - lr: 0.0010
Epoch 9/30
774/774 [==============================] - 297s 383ms/step - loss: 0.1774 - accuracy: 0.9439 - val_loss: 0.2264 - val_accuracy: 0.9378 - lr: 0.0010
Epoch 10/30
774/774 [==============================] - 297s 383ms/step - loss: 0.1584 - accuracy: 0.9487 - val_loss: 0.1706 - val_accuracy: 0.9508 - lr: 0.0010
Epoch 11/30
774/774 [==============================] - 294s 380ms/step - loss: 0.1477 - accuracy: 0.9534 - val_loss: 0.1628 - val_accuracy: 0.9542 - lr: 0.0010
Epoch 12/30
774/774 [==============================] - 296s 382ms/step - loss: 0.1445 - accuracy: 0.9536 - val_loss: 0.1516 - val_accuracy: 0.9563 - lr: 0.0010
Epoch 13/30
774/774 [==============================] - ETA: 0s - loss: 0.1306 - accuracy: 0.9593
Epoch 13: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026.
774/774 [==============================] - 299s 386ms/step - loss: 0.1306 - accuracy: 0.9593 - val_loss: 0.1493 - val_accuracy: 0.9578 - lr: 0.0010
Epoch 14/30
774/774 [==============================] - 299s 386ms/step - loss: 0.0664 - accuracy: 0.9782 - val_loss: 0.0628 - val_accuracy: 0.9796 - lr: 2.0000e-04
Epoch 15/30
774/774 [==============================] - 297s 383ms/step - loss: 0.0571 - accuracy: 0.9812 - val_loss: 0.1513 - val_accuracy: 0.9557 - lr: 2.0000e-04
Epoch 16/30
774/774 [==============================] - 296s 382ms/step - loss: 0.0571 - accuracy: 0.9815 - val_loss: 0.1062 - val_accuracy: 0.9685 - lr: 2.0000e-04
Epoch 17/30
774/774 [==============================] - 297s 384ms/step - loss: 0.0495 - accuracy: 0.9834 - val_loss: 0.0724 - val_accuracy: 0.9785 - lr: 2.0000e-04
Epoch 18/30
774/774 [==============================] - 297s 384ms/step - loss: 0.0509 - accuracy: 0.9840 - val_loss: 0.0889 - val_accuracy: 0.9717 - lr: 2.0000e-04
Epoch 19/30
774/774 [==============================] - 296s 382ms/step - loss: 0.0494 - accuracy: 0.9843 - val_loss: 0.0396 - val_accuracy: 0.9872 - lr: 2.0000e-04
Epoch 20/30
774/774 [==============================] - 295s 381ms/step - loss: 0.0450 - accuracy: 0.9857 - val_loss: 0.0523 - val_accuracy: 0.9838 - lr: 2.0000e-04
Epoch 21/30
774/774 [==============================] - 297s 383ms/step - loss: 0.0461 - accuracy: 0.9862 - val_loss: 0.0728 - val_accuracy: 0.9776 - lr: 2.0000e-04
Epoch 22/30
774/774 [==============================] - 299s 386ms/step - loss: 0.0461 - accuracy: 0.9853 - val_loss: 0.0637 - val_accuracy: 0.9815 - lr: 2.0000e-04
Epoch 23/30
774/774 [==============================] - 300s 387ms/step - loss: 0.0428 - accuracy: 0.9864 - val_loss: 0.0921 - val_accuracy: 0.9744 - lr: 2.0000e-04
Epoch 24/30
774/774 [==============================] - ETA: 0s - loss: 0.0449 - accuracy: 0.9858
Epoch 24: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05.
774/774 [==============================] - 304s 393ms/step - loss: 0.0449 - accuracy: 0.9858 - val_loss: 0.1405 - val_accuracy: 0.9612 - lr: 2.0000e-04
Epoch 25/30
774/774 [==============================] - 307s 396ms/step - loss: 0.0325 - accuracy: 0.9896 - val_loss: 0.0602 - val_accuracy: 0.9804 - lr: 4.0000e-05
Epoch 26/30
774/774 [==============================] - 304s 393ms/step - loss: 0.0278 - accuracy: 0.9912 - val_loss: 0.0841 - val_accuracy: 0.9753 - lr: 4.0000e-05
Epoch 27/30
774/774 [==============================] - 304s 393ms/step - loss: 0.0288 - accuracy: 0.9897 - val_loss: 0.0856 - val_accuracy: 0.9740 - lr: 4.0000e-05
Epoch 28/30
774/774 [==============================] - 308s 398ms/step - loss: 0.0320 - accuracy: 0.9897 - val_loss: 0.0748 - val_accuracy: 0.9761 - lr: 4.0000e-05
Epoch 29/30
774/774 [==============================] - ETA: 0s - loss: 0.0289 - accuracy: 0.9911
Epoch 29: ReduceLROnPlateau reducing learning rate to 1e-05.
774/774 [==============================] - 309s 399ms/step - loss: 0.0289 - accuracy: 0.9911 - val_loss: 0.0751 - val_accuracy: 0.9768 - lr: 4.0000e-05
Epoch 29: early stopping
In [ ]:
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
Out[ ]:
epoch loss accuracy val_loss val_accuracy lr
0 1 1.346362 0.545271 2.206433 0.453552 0.00100
1 2 0.651767 0.778289 1.765861 0.651404 0.00100
2 3 0.423353 0.859179 0.786587 0.805917 0.00100
3 4 0.332164 0.891043 0.507010 0.866026 0.00100
4 5 0.263335 0.913900 0.204228 0.933484 0.00100
5 6 0.242320 0.921533 0.622015 0.868099 0.00100
6 7 0.208308 0.933123 0.423699 0.885246 0.00100
7 8 0.183510 0.940837 0.122238 0.966836 0.00100
8 9 0.177364 0.943946 0.226416 0.937818 0.00100
9 10 0.158361 0.948671 0.170555 0.950820 0.00100
10 11 0.147676 0.953437 0.162780 0.954211 0.00100
11 12 0.144481 0.953598 0.151577 0.956284 0.00100
12 13 0.130632 0.959252 0.149276 0.957792 0.00100
13 14 0.066417 0.978192 0.062791 0.979650 0.00020
14 15 0.057136 0.981221 0.151331 0.955719 0.00020
15 16 0.057144 0.981544 0.106232 0.968532 0.00020
16 17 0.049510 0.983402 0.072435 0.978519 0.00020
17 18 0.050905 0.983967 0.088898 0.971735 0.00020
18 19 0.049367 0.984331 0.039642 0.987187 0.00020
19 20 0.044987 0.985664 0.052274 0.983795 0.00020
20 21 0.046138 0.986189 0.072773 0.977577 0.00020
21 22 0.046072 0.985260 0.063689 0.981534 0.00020
22 23 0.042846 0.986390 0.092071 0.974373 0.00020
23 24 0.044919 0.985785 0.140496 0.961183 0.00020
24 25 0.032528 0.989621 0.060175 0.980403 0.00004
25 26 0.027804 0.991196 0.084115 0.975316 0.00004
26 27 0.028785 0.989702 0.085557 0.973997 0.00004
27 28 0.031960 0.989702 0.074788 0.976069 0.00004
28 29 0.028948 0.991075 0.075122 0.976823 0.00004
In [ ]:
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)

# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()

# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
No description has been provided for this image
No description has been provided for this image

Interpreting the Model Performance¶

After training the model over 30 epochs, we were able to get an accuracy score of 99.9% on our validation dataset.

Evaluating the Model on the Test Data¶

In [ ]:
# evaluate the model
model.evaluate(test_generator)
166/166 [==============================] - 12s 74ms/step - loss: 0.0686 - accuracy: 0.9814
Out[ ]:
[0.06857447326183319, 0.9813594222068787]
In [ ]:
# predict the model
y_pred = model.predict(test_generator)

# get the class with the highest probability
y_pred_labels = np.argmax(y_pred, axis=1)

# get the true class
y_true = np.array(test_generator.classes)


# get the class labels
class_labels = list(test_generator.class_indices.keys())

# get the accuracy
accuracy = accuracy_score(y_true, y_pred_labels)
print(f'Accuracy: {accuracy}')
166/166 [==============================] - 9s 54ms/step
Accuracy: 0.9813594426661646
In [ ]:
print(classification_report(y_true, y_pred_labels, target_names=class_labels, zero_division=0))
              precision    recall  f1-score   support

       Apple       0.95      1.00      0.98       593
      Cherry       0.93      1.00      0.96       308
Corn (maize)       1.00      1.00      1.00       419
       Grape       1.00      0.99      0.99      1852
 Pepper bell       1.00      0.93      0.96       533
      Potato       0.97      0.98      0.97       622
        Rice       1.00      0.94      0.97        54
  Strawberry       0.93      0.94      0.93       227
         Tea       0.99      1.00      1.00       130
      Tomato       0.98      0.99      0.98       573

    accuracy                           0.98      5311
   macro avg       0.98      0.98      0.98      5311
weighted avg       0.98      0.98      0.98      5311

Above, we can see how the model performed. We have an accuracy of 99.8% on the test data. And then we can also see how it performed on each class.

In [ ]:
# model.save('./models/new/plant-disease-vanilla.h5')

Future Work¶

In [ ]:
from tensorflow.keras.applications import VGG16
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Flatten, GlobalAveragePooling2D

vgg_model = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
In [ ]:
# Freeze the base model
vgg_model.trainable = False

# Add custom layers on top of the base model
x = vgg_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

# Create the model
model = Model(inputs=vgg_model.input, outputs=predictions)

# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

vgg_callbacks = [
    callbacks.ModelCheckpoint(filepath='./models/newer/vgg16_vanilla.h5', save_best_only=True),
    callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
    callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]

# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=30, callbacks=vgg_callbacks)
Epoch 1/30
774/774 [==============================] - 331s 425ms/step - loss: 0.4735 - accuracy: 0.8503 - val_loss: 0.1455 - val_accuracy: 0.9550 - lr: 0.0010
Epoch 2/30
774/774 [==============================] - 332s 429ms/step - loss: 0.2484 - accuracy: 0.9174 - val_loss: 0.1095 - val_accuracy: 0.9653 - lr: 0.0010
Epoch 3/30
774/774 [==============================] - 331s 428ms/step - loss: 0.2110 - accuracy: 0.9294 - val_loss: 0.0991 - val_accuracy: 0.9672 - lr: 0.0010
Epoch 4/30
774/774 [==============================] - 330s 426ms/step - loss: 0.1963 - accuracy: 0.9348 - val_loss: 0.0828 - val_accuracy: 0.9746 - lr: 0.0010
Epoch 5/30
774/774 [==============================] - 332s 429ms/step - loss: 0.1818 - accuracy: 0.9398 - val_loss: 0.0913 - val_accuracy: 0.9697 - lr: 0.0010
Epoch 6/30
774/774 [==============================] - 332s 429ms/step - loss: 0.1761 - accuracy: 0.9410 - val_loss: 0.0843 - val_accuracy: 0.9742 - lr: 0.0010
Epoch 7/30
774/774 [==============================] - 333s 431ms/step - loss: 0.1645 - accuracy: 0.9433 - val_loss: 0.0831 - val_accuracy: 0.9706 - lr: 0.0010
Epoch 8/30
774/774 [==============================] - 335s 432ms/step - loss: 0.1659 - accuracy: 0.9431 - val_loss: 0.1222 - val_accuracy: 0.9568 - lr: 0.0010
Epoch 9/30
774/774 [==============================] - 340s 439ms/step - loss: 0.1612 - accuracy: 0.9456 - val_loss: 0.0687 - val_accuracy: 0.9772 - lr: 0.0010
Epoch 10/30
774/774 [==============================] - 339s 438ms/step - loss: 0.1470 - accuracy: 0.9488 - val_loss: 0.0780 - val_accuracy: 0.9734 - lr: 0.0010
Epoch 11/30
774/774 [==============================] - 339s 438ms/step - loss: 0.1465 - accuracy: 0.9501 - val_loss: 0.0568 - val_accuracy: 0.9821 - lr: 0.0010
Epoch 12/30
774/774 [==============================] - 362s 468ms/step - loss: 0.1461 - accuracy: 0.9505 - val_loss: 0.0613 - val_accuracy: 0.9813 - lr: 0.0010
Epoch 13/30
774/774 [==============================] - 342s 442ms/step - loss: 0.1409 - accuracy: 0.9509 - val_loss: 0.0659 - val_accuracy: 0.9766 - lr: 0.0010
Epoch 14/30
774/774 [==============================] - 341s 441ms/step - loss: 0.1357 - accuracy: 0.9529 - val_loss: 0.0790 - val_accuracy: 0.9734 - lr: 0.0010
Epoch 15/30
774/774 [==============================] - 343s 443ms/step - loss: 0.1297 - accuracy: 0.9543 - val_loss: 0.0589 - val_accuracy: 0.9821 - lr: 0.0010
Epoch 16/30
774/774 [==============================] - ETA: 0s - loss: 0.1339 - accuracy: 0.9549
Epoch 16: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026.
774/774 [==============================] - 343s 443ms/step - loss: 0.1339 - accuracy: 0.9549 - val_loss: 0.0652 - val_accuracy: 0.9793 - lr: 0.0010
Epoch 17/30
774/774 [==============================] - 347s 448ms/step - loss: 0.1103 - accuracy: 0.9624 - val_loss: 0.0553 - val_accuracy: 0.9810 - lr: 2.0000e-04
Epoch 18/30
774/774 [==============================] - 347s 449ms/step - loss: 0.1033 - accuracy: 0.9652 - val_loss: 0.0580 - val_accuracy: 0.9812 - lr: 2.0000e-04
Epoch 19/30
774/774 [==============================] - 351s 454ms/step - loss: 0.1027 - accuracy: 0.9647 - val_loss: 0.0568 - val_accuracy: 0.9787 - lr: 2.0000e-04
Epoch 20/30
774/774 [==============================] - 349s 451ms/step - loss: 0.1083 - accuracy: 0.9629 - val_loss: 0.0512 - val_accuracy: 0.9830 - lr: 2.0000e-04
Epoch 21/30
774/774 [==============================] - 351s 453ms/step - loss: 0.1038 - accuracy: 0.9658 - val_loss: 0.0600 - val_accuracy: 0.9781 - lr: 2.0000e-04
Epoch 22/30
774/774 [==============================] - 354s 457ms/step - loss: 0.0987 - accuracy: 0.9672 - val_loss: 0.0586 - val_accuracy: 0.9800 - lr: 2.0000e-04
Epoch 23/30
774/774 [==============================] - 357s 462ms/step - loss: 0.1025 - accuracy: 0.9653 - val_loss: 0.0621 - val_accuracy: 0.9804 - lr: 2.0000e-04
Epoch 24/30
774/774 [==============================] - 359s 464ms/step - loss: 0.1032 - accuracy: 0.9639 - val_loss: 0.0548 - val_accuracy: 0.9804 - lr: 2.0000e-04
Epoch 25/30
774/774 [==============================] - ETA: 0s - loss: 0.1033 - accuracy: 0.9633
Epoch 25: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05.
774/774 [==============================] - 358s 463ms/step - loss: 0.1033 - accuracy: 0.9633 - val_loss: 0.0572 - val_accuracy: 0.9813 - lr: 2.0000e-04
Epoch 26/30
774/774 [==============================] - 359s 464ms/step - loss: 0.0968 - accuracy: 0.9665 - val_loss: 0.0497 - val_accuracy: 0.9825 - lr: 4.0000e-05
Epoch 27/30
774/774 [==============================] - 362s 467ms/step - loss: 0.0950 - accuracy: 0.9675 - val_loss: 0.0510 - val_accuracy: 0.9827 - lr: 4.0000e-05
Epoch 28/30
774/774 [==============================] - 360s 465ms/step - loss: 0.0982 - accuracy: 0.9654 - val_loss: 0.0506 - val_accuracy: 0.9834 - lr: 4.0000e-05
Epoch 29/30
774/774 [==============================] - 358s 463ms/step - loss: 0.0966 - accuracy: 0.9664 - val_loss: 0.0501 - val_accuracy: 0.9829 - lr: 4.0000e-05
Epoch 30/30
774/774 [==============================] - 355s 459ms/step - loss: 0.0946 - accuracy: 0.9671 - val_loss: 0.0513 - val_accuracy: 0.9815 - lr: 4.0000e-05
In [ ]:
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
Out[ ]:
epoch loss accuracy val_loss val_accuracy lr
0 1 0.473496 0.850335 0.145496 0.954965 0.00100
1 2 0.248432 0.917373 0.109509 0.965329 0.00100
2 3 0.211032 0.929408 0.099066 0.967213 0.00100
3 4 0.196292 0.934819 0.082777 0.974562 0.00100
4 5 0.181791 0.939787 0.091314 0.969663 0.00100
5 6 0.176082 0.940998 0.084296 0.974185 0.00100
6 7 0.164489 0.943341 0.083059 0.970605 0.00100
7 8 0.165904 0.943098 0.122178 0.956849 0.00100
8 9 0.161170 0.945562 0.068655 0.977200 0.00100
9 10 0.147003 0.948793 0.078003 0.973431 0.00100
10 11 0.146516 0.950085 0.056824 0.982099 0.00100
11 12 0.146131 0.950489 0.061275 0.981345 0.00100
12 13 0.140935 0.950852 0.065926 0.976635 0.00100
13 14 0.135654 0.952871 0.079004 0.973431 0.00100
14 15 0.129676 0.954325 0.058877 0.982099 0.00100
15 16 0.133877 0.954931 0.065177 0.979273 0.00100
16 17 0.110282 0.962362 0.055346 0.980969 0.00020
17 18 0.103291 0.965229 0.058031 0.981157 0.00020
18 19 0.102651 0.964704 0.056849 0.978707 0.00020
19 20 0.108301 0.962887 0.051188 0.983041 0.00020
20 21 0.103799 0.965794 0.059951 0.978142 0.00020
21 22 0.098665 0.967167 0.058564 0.980026 0.00020
22 23 0.102459 0.965269 0.062096 0.980403 0.00020
23 24 0.103229 0.963856 0.054762 0.980403 0.00020
24 25 0.103273 0.963291 0.057197 0.981345 0.00020
25 26 0.096757 0.966481 0.049681 0.982476 0.00004
26 27 0.094969 0.967531 0.051033 0.982664 0.00004
27 28 0.098184 0.965431 0.050577 0.983418 0.00004
28 29 0.096563 0.966400 0.050056 0.982853 0.00004
29 30 0.094638 0.967127 0.051328 0.981534 0.00004
In [ ]:
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)

# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()

# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
No description has been provided for this image
No description has been provided for this image
In [ ]:
# evaluate the model
model.evaluate(test_generator)
166/166 [==============================] - 15s 87ms/step - loss: 0.0451 - accuracy: 0.9840
Out[ ]:
[0.045121122151613235, 0.9839954972267151]
In [ ]:
from tensorflow.keras.applications import ResNet50

resnet_model = ResNet50(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
In [ ]:
# Freeze the base model
resnet_model.trainable = False

# Add custom layers on top of the base model
x = resnet_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

# Create the model
model = Model(inputs=resnet_model.input, outputs=predictions)

# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

resnet_callbacks = [
    callbacks.ModelCheckpoint(filepath='./models/newer/resnet.h5', save_best_only=True),
    callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
    callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]

# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=30, callbacks=resnet_callbacks)
Epoch 1/30
774/774 [==============================] - 358s 459ms/step - loss: 1.9210 - accuracy: 0.3603 - val_loss: 1.8186 - val_accuracy: 0.4341 - lr: 0.0010
Epoch 2/30
774/774 [==============================] - 357s 461ms/step - loss: 1.7845 - accuracy: 0.3877 - val_loss: 1.5984 - val_accuracy: 0.4113 - lr: 0.0010
Epoch 3/30
774/774 [==============================] - 355s 458ms/step - loss: 1.6830 - accuracy: 0.4166 - val_loss: 1.4394 - val_accuracy: 0.5031 - lr: 0.0010
Epoch 4/30
774/774 [==============================] - 357s 461ms/step - loss: 1.5690 - accuracy: 0.4568 - val_loss: 1.3823 - val_accuracy: 0.5483 - lr: 0.0010
Epoch 5/30
774/774 [==============================] - 357s 461ms/step - loss: 1.4822 - accuracy: 0.4914 - val_loss: 1.2077 - val_accuracy: 0.6243 - lr: 0.0010
Epoch 6/30
774/774 [==============================] - 352s 455ms/step - loss: 1.4092 - accuracy: 0.5166 - val_loss: 1.2771 - val_accuracy: 0.5753 - lr: 0.0010
Epoch 7/30
774/774 [==============================] - 358s 462ms/step - loss: 1.3472 - accuracy: 0.5403 - val_loss: 1.3529 - val_accuracy: 0.5432 - lr: 0.0010
Epoch 8/30
774/774 [==============================] - 360s 465ms/step - loss: 1.3016 - accuracy: 0.5565 - val_loss: 1.3384 - val_accuracy: 0.5613 - lr: 0.0010
Epoch 9/30
774/774 [==============================] - 349s 451ms/step - loss: 1.2843 - accuracy: 0.5609 - val_loss: 1.2331 - val_accuracy: 0.6007 - lr: 0.0010
Epoch 10/30
774/774 [==============================] - ETA: 0s - loss: 1.2398 - accuracy: 0.5767
Epoch 10: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026.
774/774 [==============================] - 535s 692ms/step - loss: 1.2398 - accuracy: 0.5767 - val_loss: 1.2863 - val_accuracy: 0.5719 - lr: 0.0010
Epoch 11/30
774/774 [==============================] - 599s 773ms/step - loss: 1.1618 - accuracy: 0.6092 - val_loss: 1.2851 - val_accuracy: 0.5824 - lr: 2.0000e-04
Epoch 12/30
774/774 [==============================] - 5608s 7s/step - loss: 1.1628 - accuracy: 0.6084 - val_loss: 1.3966 - val_accuracy: 0.5338 - lr: 2.0000e-04
Epoch 13/30
774/774 [==============================] - 682s 880ms/step - loss: 1.1558 - accuracy: 0.6117 - val_loss: 1.4318 - val_accuracy: 0.5293 - lr: 2.0000e-04
Epoch 14/30
774/774 [==============================] - 292s 378ms/step - loss: 1.1432 - accuracy: 0.6140 - val_loss: 1.4195 - val_accuracy: 0.5267 - lr: 2.0000e-04
Epoch 15/30
774/774 [==============================] - ETA: 0s - loss: 1.1404 - accuracy: 0.6171
Epoch 15: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05.
774/774 [==============================] - 291s 376ms/step - loss: 1.1404 - accuracy: 0.6171 - val_loss: 1.4003 - val_accuracy: 0.5466 - lr: 2.0000e-04
Epoch 15: early stopping
In [ ]:
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
Out[ ]:
epoch loss accuracy val_loss val_accuracy lr
0 1 1.921015 0.360270 1.818613 0.434144 0.0010
1 2 1.784497 0.387731 1.598449 0.411344 0.0010
2 3 1.682990 0.416646 1.439388 0.503109 0.0010
3 4 1.569026 0.456829 1.382310 0.548332 0.0010
4 5 1.482225 0.491358 1.207664 0.624270 0.0010
5 6 1.409242 0.516598 1.277117 0.575278 0.0010
6 7 1.347218 0.540263 1.352898 0.543245 0.0010
7 8 1.301566 0.556538 1.338384 0.561334 0.0010
8 9 1.284263 0.560940 1.233055 0.600716 0.0010
9 10 1.239771 0.576730 1.286306 0.571886 0.0010
10 11 1.161845 0.609200 1.285128 0.582438 0.0002
11 12 1.162829 0.608392 1.396613 0.533823 0.0002
12 13 1.155751 0.611703 1.431812 0.529301 0.0002
13 14 1.143228 0.613965 1.419468 0.526663 0.0002
14 15 1.140438 0.617075 1.400278 0.546637 0.0002
In [ ]:
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)

# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()

# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
No description has been provided for this image
No description has been provided for this image
In [ ]:
from tensorflow.keras.applications import InceptionV3

inception_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
In [ ]:
# Freeze the base model
inception_model.trainable = False

# Add custom layers on top of the base model
x = inception_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

# Create the model
model = Model(inputs=inception_model.input, outputs=predictions)

# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

inception_callbacks = [
    callbacks.ModelCheckpoint(filepath='./models/newer/inception.h5', save_best_only=True),
    callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
    callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]

# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=10, callbacks=inception_callbacks)
Epoch 1/10
774/774 [==============================] - 306s 391ms/step - loss: 0.3652 - accuracy: 0.8914 - val_loss: 0.1458 - val_accuracy: 0.9516 - lr: 0.0010
Epoch 2/10
774/774 [==============================] - 305s 394ms/step - loss: 0.2088 - accuracy: 0.9336 - val_loss: 0.1328 - val_accuracy: 0.9587 - lr: 0.0010
Epoch 3/10
774/774 [==============================] - 306s 395ms/step - loss: 0.1767 - accuracy: 0.9420 - val_loss: 0.1056 - val_accuracy: 0.9653 - lr: 0.0010
Epoch 4/10
774/774 [==============================] - 305s 394ms/step - loss: 0.1616 - accuracy: 0.9458 - val_loss: 0.0891 - val_accuracy: 0.9708 - lr: 0.0010
Epoch 5/10
774/774 [==============================] - 305s 394ms/step - loss: 0.1588 - accuracy: 0.9487 - val_loss: 0.0907 - val_accuracy: 0.9714 - lr: 0.0010
Epoch 6/10
774/774 [==============================] - 303s 391ms/step - loss: 0.1503 - accuracy: 0.9502 - val_loss: 0.0718 - val_accuracy: 0.9763 - lr: 0.0010
Epoch 7/10
774/774 [==============================] - 303s 391ms/step - loss: 0.1387 - accuracy: 0.9542 - val_loss: 0.0725 - val_accuracy: 0.9768 - lr: 0.0010
Epoch 8/10
774/774 [==============================] - 386s 499ms/step - loss: 0.1397 - accuracy: 0.9544 - val_loss: 0.0598 - val_accuracy: 0.9808 - lr: 0.0010
Epoch 9/10
774/774 [==============================] - 434s 561ms/step - loss: 0.1338 - accuracy: 0.9554 - val_loss: 0.0574 - val_accuracy: 0.9804 - lr: 0.0010
Epoch 10/10
774/774 [==============================] - 321s 415ms/step - loss: 0.1302 - accuracy: 0.9582 - val_loss: 0.0643 - val_accuracy: 0.9780 - lr: 0.0010
In [ ]:
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
Out[ ]:
epoch loss accuracy val_loss val_accuracy lr
0 1 0.365223 0.891366 0.145790 0.951573 0.001
1 2 0.208753 0.933608 0.132835 0.958734 0.001
2 3 0.176746 0.942048 0.105626 0.965329 0.001
3 4 0.161572 0.945844 0.089074 0.970793 0.001
4 5 0.158773 0.948712 0.090716 0.971359 0.001
5 6 0.150257 0.950246 0.071814 0.976258 0.001
6 7 0.138736 0.954164 0.072514 0.976823 0.001
7 8 0.139679 0.954366 0.059811 0.980780 0.001
8 9 0.133834 0.955416 0.057398 0.980403 0.001
9 10 0.130176 0.958162 0.064259 0.977954 0.001
In [ ]:
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)

# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()

# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
No description has been provided for this image
No description has been provided for this image
In [ ]:
# evaluate the model
model.evaluate(test_generator)
166/166 [==============================] - 11s 67ms/step - loss: 0.0688 - accuracy: 0.9782
Out[ ]:
[0.06876641511917114, 0.9781585335731506]
In [ ]:
from tensorflow.keras.applications import Xception

efficient_model = Xception(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/xception/xception_weights_tf_dim_ordering_tf_kernels_notop.h5
83683744/83683744 [==============================] - 26s 0us/step
In [ ]:
# Freeze the base model
efficient_model.trainable = False

# Add custom layers on top of the base model
x = efficient_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

# Create the model
model = Model(inputs=efficient_model.input, outputs=predictions)

# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

efficient_callbacks = [
    callbacks.ModelCheckpoint(filepath='./models/newer/efficient.h5', save_best_only=True),
    callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
    callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]

# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=15, callbacks=efficient_callbacks)
Epoch 1/15
774/774 [==============================] - 316s 406ms/step - loss: 0.2653 - accuracy: 0.9118 - val_loss: 0.1146 - val_accuracy: 0.9617 - lr: 0.0010
Epoch 2/15
774/774 [==============================] - 307s 397ms/step - loss: 0.1586 - accuracy: 0.9480 - val_loss: 0.0836 - val_accuracy: 0.9714 - lr: 0.0010
Epoch 3/15
774/774 [==============================] - 310s 400ms/step - loss: 0.1366 - accuracy: 0.9559 - val_loss: 0.0994 - val_accuracy: 0.9650 - lr: 0.0010
Epoch 4/15
774/774 [==============================] - 314s 406ms/step - loss: 0.1243 - accuracy: 0.9596 - val_loss: 0.0797 - val_accuracy: 0.9749 - lr: 0.0010
Epoch 5/15
774/774 [==============================] - 309s 399ms/step - loss: 0.1154 - accuracy: 0.9607 - val_loss: 0.0854 - val_accuracy: 0.9702 - lr: 0.0010
Epoch 6/15
774/774 [==============================] - 323s 417ms/step - loss: 0.1054 - accuracy: 0.9641 - val_loss: 0.0850 - val_accuracy: 0.9714 - lr: 0.0010
Epoch 7/15
774/774 [==============================] - 339s 438ms/step - loss: 0.1044 - accuracy: 0.9651 - val_loss: 0.0915 - val_accuracy: 0.9689 - lr: 0.0010
Epoch 8/15
774/774 [==============================] - 363s 469ms/step - loss: 0.1003 - accuracy: 0.9665 - val_loss: 0.0498 - val_accuracy: 0.9834 - lr: 0.0010
Epoch 9/15
774/774 [==============================] - 306s 396ms/step - loss: 0.0977 - accuracy: 0.9684 - val_loss: 0.0588 - val_accuracy: 0.9810 - lr: 0.0010
Epoch 10/15
774/774 [==============================] - 305s 395ms/step - loss: 0.0941 - accuracy: 0.9693 - val_loss: 0.0511 - val_accuracy: 0.9838 - lr: 0.0010
Epoch 11/15
774/774 [==============================] - 308s 398ms/step - loss: 0.0851 - accuracy: 0.9722 - val_loss: 0.0524 - val_accuracy: 0.9842 - lr: 0.0010
Epoch 12/15
774/774 [==============================] - 312s 403ms/step - loss: 0.0899 - accuracy: 0.9713 - val_loss: 0.0685 - val_accuracy: 0.9785 - lr: 0.0010
Epoch 13/15
774/774 [==============================] - 308s 397ms/step - loss: 0.0880 - accuracy: 0.9710 - val_loss: 0.0465 - val_accuracy: 0.9845 - lr: 0.0010
Epoch 14/15
774/774 [==============================] - 311s 401ms/step - loss: 0.0801 - accuracy: 0.9737 - val_loss: 0.0503 - val_accuracy: 0.9845 - lr: 0.0010
Epoch 15/15
774/774 [==============================] - 311s 402ms/step - loss: 0.0774 - accuracy: 0.9751 - val_loss: 0.0478 - val_accuracy: 0.9827 - lr: 0.0010
In [ ]:
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
Out[ ]:
epoch loss accuracy val_loss val_accuracy lr
0 1 0.265340 0.911841 0.114605 0.961749 0.001
1 2 0.158584 0.948025 0.083582 0.971359 0.001
2 3 0.136570 0.955900 0.099449 0.964952 0.001
3 4 0.124294 0.959575 0.079673 0.974939 0.001
4 5 0.115392 0.960706 0.085360 0.970228 0.001
5 6 0.105406 0.964058 0.084982 0.971359 0.001
6 7 0.104378 0.965148 0.091515 0.968909 0.001
7 8 0.100327 0.966481 0.049812 0.983418 0.001
8 9 0.097743 0.968379 0.058797 0.980969 0.001
9 10 0.094106 0.969308 0.051137 0.983795 0.001
10 11 0.085105 0.972175 0.052445 0.984172 0.001
11 12 0.089946 0.971287 0.068457 0.978519 0.001
12 13 0.087987 0.971044 0.046454 0.984549 0.001
13 14 0.080096 0.973669 0.050293 0.984549 0.001
14 15 0.077437 0.975083 0.047846 0.982664 0.001
In [ ]:
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)

# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()

# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')

plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
No description has been provided for this image
No description has been provided for this image
In [ ]:
model.evaluate(test_generator)
166/166 [==============================] - 10s 61ms/step - loss: 0.0504 - accuracy: 0.9810
Out[ ]:
[0.050435829907655716, 0.9809828400611877]